package software.hust.com.hust_last.util.oss;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider;
import com.alibaba.sdk.android.oss.model.GetObjectRequest;
import com.alibaba.sdk.android.oss.model.GetObjectResult;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import software.hust.com.hust_last.util.FileUtil;
import software.hust.com.hust_last.util.LogUtil;

public class OssFileOperator {

    private static final String TAG = "OssFileOperator";

    private static OSSClient sOSSClient;
    private static Handler sHandler;
    private static Context sApplicationContext;

    private static LruCache<String, Bitmap> sImageCache;

    public static void init(Context context) {
        sApplicationContext = context.getApplicationContext();
        OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(
                OssConfig.ACCESS_KEY_ID, OssConfig.ACCESS_KEY_SECRET);
        sOSSClient = new OSSClient(sApplicationContext, OssConfig.END_POINT,
                credentialProvider);
        sHandler = new Handler();
        sImageCache = new LruCache<String, Bitmap>((int) (Runtime.getRuntime().maxMemory() / 8)) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    public static void loadImage(ImageView imageView, String url) {
        imageView.setTag(url);
        Bitmap bitmap = sImageCache.get(url);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            LogUtil.i(TAG, "load image from cache");
            return;
        }
        download(url, new OssImageCallback(imageView));
    }

    public static void download(final String url, final OssCallback callback) {
        File cacheFile = FileUtil.getCacheFile(sApplicationContext, url);
        if (cacheFile != null) {
            callback.onSuccess(url, cacheFile);
            LogUtil.i(TAG, "load image from disk");
            return;
        }
        GetObjectRequest get = new GetObjectRequest(OssConfig.BUCKET_NAME, url);
        get.setProgressListener(new OSSProgressCallback<GetObjectRequest>() {
            @Override
            public void onProgress(GetObjectRequest request, final long currentSize, final long totalSize) {
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onProgress(currentSize, totalSize);
                    }
                });
            }
        });
        sOSSClient.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() {
            @Override
            public void onSuccess(GetObjectRequest request, GetObjectResult result) {
                final File file = FileUtil.saveFile(sApplicationContext, url, result.getObjectContent());
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onSuccess(url, file);
                        LogUtil.i(TAG, "load image from network");
                    }
                });
            }

            @Override
            public void onFailure(GetObjectRequest request, ClientException clientException, final ServiceException serviceException) {
                String errMsg = "";
                if (clientException != null) {
                    // 本地异常
                    errMsg = "网络异常";
                    clientException.printStackTrace();
                } else if (serviceException != null) {
                    errMsg = "服务异常 " + serviceException.getErrorCode();
                    Log.e("OssFileOperator", serviceException.toString());
                }
                final String msg = errMsg;
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailure(msg);
                    }
                });
            }
        });
    }

    public static void loadThumbnail(ImageView imageView, String url) {
        String thumbnailUrl = url + "_thumbnail";
        imageView.setTag(thumbnailUrl);
        Bitmap bitmap = sImageCache.get(thumbnailUrl);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            LogUtil.i(TAG, "load image from cache :" + thumbnailUrl);
            return;
        }
        downloadThumbnail(url, new OssImageCallback(imageView));
    }

    private static void downloadThumbnail(final String url, final OssCallback callback) {
        final String thumbnailUrl = url + "_thumbnail";
        File cacheFile = FileUtil.getCacheFile(sApplicationContext, thumbnailUrl);
        if (cacheFile != null) {
            callback.onSuccess(thumbnailUrl, cacheFile);
            LogUtil.i(TAG, "load image from disk : " + thumbnailUrl);
            return;
        }
        GetObjectRequest get = new GetObjectRequest(OssConfig.BUCKET_NAME, url);
        get.setxOssProcess("image/resize,p_20");
        get.setProgressListener(new OSSProgressCallback<GetObjectRequest>() {
            @Override
            public void onProgress(GetObjectRequest request, final long currentSize, final long totalSize) {
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onProgress(currentSize, totalSize);
                    }
                });
            }
        });
        sOSSClient.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() {
            @Override
            public void onSuccess(GetObjectRequest request, GetObjectResult result) {
                final File file = FileUtil.saveFile(sApplicationContext, thumbnailUrl, result.getObjectContent());
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onSuccess(thumbnailUrl, file);
                        LogUtil.i(TAG, "load image from network");
                    }
                });
            }

            @Override
            public void onFailure(GetObjectRequest request, ClientException clientException, final ServiceException serviceException) {
                String errMsg = "";
                if (clientException != null) {
                    // 本地异常
                    errMsg = "网络异常";
                    clientException.printStackTrace();
                } else if (serviceException != null) {
                    errMsg = "服务异常 " + serviceException.getErrorCode();
                    Log.e("OssFileOperator", serviceException.toString());
                }
                final String msg = errMsg;
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailure(msg);
                    }
                });
            }
        });
    }

    public static void putToImageCache(String url, Bitmap bitmap) {
        sImageCache.put(url, bitmap);
    }

    public static void upload(final String url, final String uploadFilePath, final OssCallback callback) {
        PutObjectRequest put = new PutObjectRequest(OssConfig.BUCKET_NAME, url, uploadFilePath);
        put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
            @Override
            public void onProgress(PutObjectRequest request, final long currentSize, final long totalSize) {
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onProgress(currentSize, totalSize);
                    }
                });
            }
        });
        sOSSClient.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
            @Override
            public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onSuccess(url, new File(uploadFilePath));
                    }
                });
            }

            @Override
            public void onFailure(PutObjectRequest request, ClientException clientException, ServiceException serviceException) {
                String errMsg = "";
                if (clientException != null) {
                    // 本地异常
                    errMsg = "网络异常";
                    clientException.printStackTrace();
                } else if (serviceException != null) {
                    errMsg = "服务异常 " + serviceException.getErrorCode();
                    Log.e("OssFileOperator", serviceException.toString());
                }
                final String msg = errMsg;
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailure(msg);
                    }
                });
            }
        });
    }

    public static void uploadBatch(List<String> urls, List<String> uploadFiles, OssUploadBatchCallback callback) {
        innerUploadBatch(urls, uploadFiles, new ArrayList<String>(), callback);
    }

    private static void innerUploadBatch(final List<String> urls, final List<String> uploadFiles, final List<String> failFiles, final OssUploadBatchCallback callback) {
        if (uploadFiles.isEmpty()) {
            sHandler.post(new Runnable() {
                @Override
                public void run() {
                    callback.onResult(urls.size() - failFiles.size(), failFiles.size(), failFiles);
                }
            });
            return;
        }
        String url = urls.get(0);
        urls.remove(0);
        String uploadFilePath = uploadFiles.get(0);
        uploadFiles.remove(0);

        PutObjectRequest put = new PutObjectRequest(OssConfig.BUCKET_NAME, url, uploadFilePath);
        sOSSClient.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
            @Override
            public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                callback.onProgress(urls.size() - uploadFiles.size(), urls.size());
                innerUploadBatch(urls, uploadFiles, failFiles, callback);
            }

            @Override
            public void onFailure(PutObjectRequest request, ClientException clientException, ServiceException serviceException) {
                failFiles.add(request.getUploadFilePath());
                callback.onProgress(urls.size() - uploadFiles.size(), urls.size());
                innerUploadBatch(urls, uploadFiles, failFiles, callback);
            }
        });
    }

    /**
     * 根据Oss相对路径获取外部可访问的Url
     */
    public String getPublicUrl(String url) {
        return sOSSClient.presignPublicObjectURL(OssConfig.BUCKET_NAME, url);
    }
}
